#pragma once

#include <iostream>
#include <functional>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "err.hpp"

class TcpServer
{
    static const int backlog = 32;
    static const size_t BUF_SIZE = 1024;
    using func_t = std::function<std::string(std::string)>;

public:
    TcpServer(func_t service, uint16_t svr_port)
        : _service(service), _svr_port(svr_port)
    {
    }

    void Initial()
    {
        // 1.创建套接字
        if ((_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        {
            std::cerr << "socket create fail: " << strerror(errno) << std::endl;
            exit(SOCKET_ERR);
        }

        // 2.绑定服务器本地地址
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_svr_port);
        local.sin_addr.s_addr = INADDR_ANY;

        if (bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
        {
            std::cerr << "bind fail: " << strerror(errno) << std::endl;
            exit(BIND_ERR);
        }

        // 3.监听
        if (listen(_sockfd, backlog) < 0)
        {
            std::cerr << "listen fail: " << strerror(errno) << std::endl;
            exit(LISTEN_ERR);
        }
    }

    void Start()
    {
        struct sockaddr_in client;
        bzero(&client, sizeof(client));
        socklen_t len = sizeof(client);

        // 1.接受监听的客户端
        int cfd = accept(_sockfd, (struct sockaddr *)&client, &len);
        std::cout << "cfd: " << cfd << std::endl;
        while (true)
        {
            // struct sockaddr_in client;
            // bzero(&client, sizeof(client));
            // socklen_t len = sizeof(client);

            // // 1.接受监听的客户端
            // int cfd = accept(_sockfd, (struct sockaddr *)&client, &len);
            // if (cfd < 0)
            // {
            //     // no client connect, continue try to accept
            //     continue;
            // }
            // std::cout << "cfd: " << cfd << std::endl;

            // 2.读取客户端数据
            char buf[BUF_SIZE];
            memset(buf, 0, sizeof(buf));
            std::string respond;
            ssize_t n = read(cfd, buf, sizeof(buf) - 1);
            if (n < 0)
            {
                // read fail
                std::cerr << "read from client fail: " << strerror(errno) << std::endl;
                exit(READ_ERR);
            }
            else if (n == 0)
            {
                // client close
                close(cfd);
                std::cout << "client already closed" << std::endl;
                // try to accept again
                continue;
            }
            else
            {
                buf[n] = '\0';
                std::cout << "message from client: " << buf << std::endl;
                // read success
                // 对客户端数据进行业务处理
                respond = _service(buf);
            }

            // 3.向客户端发回数据
            n = write(cfd, respond.c_str(), respond.size());
            if (n < 0)
            {
                // write fail
                std::cerr << "write to client fail: " << strerror(errno) << std::endl;
                exit(WRITE_ERR);
            }
        }
    }

private:
    int _sockfd;
    uint16_t _svr_port;
    func_t _service;
};